﻿using MysToolCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace FundHelper.Model
{

    public static partial class Indicator
    {
        public static IEnumerable<AFResult> GetAFResult(this IEnumerable<(DateTime date, double price)> list, int period)
        {
            var tuples = list.ToList();
            if (tuples.Count <= period)
                throw new ArgumentException("无足够的数据计算后续增长率");
            var his = tuples.OrderByDescending(a => a.date).ToList();

            AFResult[] result = new AFResult[his.Count() - period];
            
            for (int i = 0; i < result.Length; i++)
            {
                if (i < period)
                {
                    result[i] = new AFResult(his[i].date, period)
                    {
                        Value = 0,
                        Max=0,
                        Min=0,
                    };
                    continue;
                }
                //计算未来就不包含当前日期
                var periodPrices = his.ToList().GetRange(i-period, period).ToList();
                double dwjz = his[i].price;
                int newIdx = i - period;
                double zzl = 100f * ((periodPrices.First().price / dwjz) - 1);
                
                var max = periodPrices.Max(a => a.price);
                var min = periodPrices.Min(a => a.price);
                var maxZZL= 100f * ((max/ dwjz) - 1);
                var minZZL= 100f * ((min / dwjz) - 1);
                result[i] = new AFResult(his[i].date, period)
                {
                    Value=zzl,
                    Max= maxZZL,
                    Min= minZZL
                };
            }
            return result;
        }
    }


    public class AFResult
    {
        public static Dictionary<string, double[]> AF5Dic = new Dictionary<string, double[]>();

        private double value;
        private double max;
        private double min;


        public DateTime dateTime { get; init; }
        public int Period { get; init; }
        [IndicatorName("af")]
        public double Value { get => value; set => this.value = value; }

        [IndicatorName("afmax")]

        public double Max { get => max; set => max = value; }
        [IndicatorName("afmin")]
        public double Min { get => min; set => min = value; }

        public AFResult(DateTime dateTime, int period)
        {
            this.dateTime = dateTime;
            this.Period = period;
        }

       
    }

    public class AF
    {

        public double AF5;
        public double AF10;
        public double AF5MAX;
        public double AF5MIN;
        public double AF10MAX;
        public double AF10MIN;
        public bool Has5 = false;
        public bool Has10 = false;


        public DateTime today;
        public double dwjz;
        public List<FundHistory> his;


        public AF(List<FundHistory> his, DateTime today, double dwjz)
        {
            this.his = his.OrderBy(a => a.date).ToList();
            this.today = today;
            //if (dwjz == null)
            //{
            //    this.dwjz = his.First(a => a.date == today).dwjz;
            //}
            //else
            //{
            this.dwjz = dwjz;
            //}
        }

        public AF Process()
        {
            var afFund = his.FindAll(a => a.date > today);
            if (afFund.Count >= 5)
            {
                Has5 = true;
                AF5 = 100 * (afFund[4].dwjz / dwjz - 1);
                var d5 = afFund.Take(5).ToList();
                var d5Max = d5.Max(a => a.dwjz);
                var d5Min = d5.Min(a => a.dwjz);

                AF5MAX = 100 * (d5Max - dwjz) / dwjz;
                AF5MIN = 100 * (d5Min - dwjz) / dwjz;
            }
            if (afFund.Count >= 10)
            {
                Has10 = true;
                AF10 = 100 * (afFund[9].dwjz / dwjz - 1);
                var d10 = afFund.Take(10).ToList();
                var d10Max = d10.Max(a => a.dwjz);
                var d10Min = d10.Min(a => a.dwjz);
                AF10MAX = 100 * (d10Max - dwjz) / dwjz;
                AF10MIN = 100 * (d10Min - dwjz) / dwjz;
            }

            return this;
        }
        public AF Print()
        {
            if (!Has5)
                return this;
            MyConsole.Write($"AF5：{AF5.Str()}", AF5 > 0);
            MyConsole.Write($" AF5MIN：{AF5MIN.Str()}", AF5MIN > 0);
            MyConsole.WriteLine($" AF5MAX：{AF5MAX.Str()}", AF5MAX > 0);
            if (!Has10)
                return this;
            MyConsole.Write($"AF10：{AF10.Str()}", AF10 > 0);
            MyConsole.Write($" AF10MIN：{AF10MIN.Str()}", AF10MIN > 0);
            MyConsole.WriteLine($" AF10MAX：{AF10MAX.Str()}", AF10MAX > 0);
            return this;
        }

    }
}
